import json
from collections import defaultdict

import numpy as np

import networkx as nx  # 用于创建和操作图结构
import heapq          # 用于实现优先队列（Dijkstra算法）
from flow1 import TrafficGenerator
from switchesalgo import allocate_switches_with_es
from topo1 import build_hybrid_topology_shared_tor


def find_min_max_delay_path(G, source, target, flow):
    """
    在电网络中寻找最大传输时延最小的路径（路径时延由瓶颈链路决定）
    :param G: 网络拓扑图（包含电链路属性）
    :param source: 源节点
    :param target: 目标节点
    :param flow: 流量需求（单位：Gbps）
    :return: 最优路径（列表）和最大时延（单位：ms）
    """
    # 初始化数据结构
    # G=build_hybrid_topology_shared_tor(num_tor=4)
    dist = {node: float('inf') for node in G.nodes()}  # 记录到达节点的最小最大时延
    print("初始化数据结构的值：",dist) # 输出所有的节点的初始最大时延
    dist[source] = 0  # 源节点时延初始化为0
    heap = [(0, source, [source])]  # 优先队列：(当前最大时延, 当前节点, 路径)
    visited = set()  # 已访问节点集合

    print("==========在find_min_max_delay_path函数中获取到的每条链路的容量大小===================")
    for u, v in G.edges():
        if G[u][v].get('type') == 'electrical':
            capacity_e = G[u][v].get('capacity', 0)
            # print(f"获取电链路{u}-{v}的容量为{capacity_e}")
        else:
            capacity_o = G[u][v].get('capacity', 0)
            # print(f"获取光链路{u}-{v}的容量为{capacity_o}")
    print("==========在find_min_max_delay_path函数中获取到的每条链路的容量大小===================")

    # 主循环：处理优先队列
    while heap:
        # 当前延迟最大值、当前节点、路径
        current_max, u, path = heapq.heappop(heap)  # 弹出当前最优路径
        # print(f"当前延迟最大值{current_max}、当前节点{u}、路径{path}")
        if u in visited:
            # print(f"{u}已访问，跳过该节点")
            continue  # 跳过已访问节点
        visited.add(u)
        # print(f"将当前节点加入已访问节点")
        # 找到目标节点返回路径
        if u == target:
            # print(f"当前访问节点为目标节点，所以找到目标节点{target}，路径为{path}")
            return path  # 找到目标节点，返回路径

        # 遍历邻居节点
        for v in G.neighbors(u):
            if G[u][v].get('type') != 'electrical':
                # print(f"{u}的邻居节点为{v},并且连接链路为光链路")
                continue  # 仅处理电链路

            capacity_e = G[u][v].get('capacity', 0)
            # print(f"获取链路{u}-{v}的电链路容量为{capacity_e}")
            if capacity_e <= 0:
                continue  # 忽略无效容量

            edge_delay = flow / capacity_e  # 计算链路时延（流量/容量）
            # print(f"链路{u}-{v}的时延为{edge_delay}")
            new_max = max(current_max, edge_delay)  # 更新路径最大时延
            # print(f"更新路径最大时延为{new_max}")

            # 松弛操作：更新邻居节点的最优时延
            if new_max < dist.get(v, float('inf')):
                dist[v] = new_max
                # print(f"更新邻居节点{v}的最优时延为{new_max}")
                heapq.heappush(heap, (new_max, v, path + [v]))  # 将新路径加入队列
                # print(f"将新路径加入队列，当前延迟最大值{new_max}、当前节点{v}、路径{path + [v]}")

    return None  # 无可用路径


def optimize_reconfiguration(new_demand_matrix, network_topology, old_optimal_paths, new_optimal_paths):
    """
    动态流量重构优化算法
    :param new_demand_matrix: 新的流量需求矩阵（字典，键为通信对，值为流量需求）
    :param network_topology: 光电混合网络拓扑（NetworkX图）
    :param old_optimal_paths: 旧的最优路径集合（字典，键为通信对，值为路径列表）
    :param new_optimal_paths: 新的最优路径集合（字典，键为通信对，值为路径列表）
    :return: 重构期间的路径集合和时延集合（均为字典）
    """
    # Step 1: 确定需要重构的通信对（新旧路径不同的通信对）
    recon_pairs = [] # 定义重构通信对集合
    no_recon_pairs = [] # 定义不需要重构的通信对集合
    link_usage = defaultdict(int)  # 记录不需要重构通信对的电链路使用量
    # no_delays = {}
    for pair in new_demand_matrix:
        old_path = old_optimal_paths.get(pair, [])
        new_path = new_optimal_paths.get(pair, [])

        # 检查路径是否有效：
        # 检查路径有效性
        if not isinstance(old_path, list) or len(old_path) < 2:
            print(f"警告：通信对 {pair} 的旧路径无效")
            continue
        if not isinstance(new_path, list) or len(new_path) < 2:
            print(f"警告：通信对 {pair} 的新路径无效")
            continue

        # if not old_path or not new_path:
        #     continue
        if old_path != new_path:
            recon_pairs.append(pair)
            # print(f"需要重构通信对：{pair}")
        else:
            no_recon_pairs.append(pair)
            print(f"不需要重构通信对：{pair}")
            # 对不需要重构的通信对占用的电链路更新容量
            # 定义不需要重构的通信对的延迟
            # no_delays={}
            # max_no_delay = 0
            # 收集旧路径中的电链路使用量
            for i in range(len(old_path) - 1):
                u=old_path[i]
                v=old_path[i+1]
                # 检查图中是否有边
                if network_topology.has_edge(u, v):
                    # print(f"边存在")
                    if network_topology[u][v].get('type') == 'electrical':
                        print(f"边{u}-{v}为电链路")
                        link_usage[(u, v)] += new_demand_matrix[pair]

                #         # 更新电链路容量
                #         if network_topology[u][v].get('capacity') is not None:
                #             # print(f"获取电链路{u}-{v}的容量为{G[u][v]['capacity']}")
                #             network_topology[u][v]['capacity'] -= new_demand_matrix[pair]
                #             no_delay=new_demand_matrix[pair]/network_topology[u][v]['capacity']
                #             max_no_delay=max(max_no_delay,no_delay)
                #             print(f"更新电链路{u}-{v}的容量为{network_topology[u][v]['capacity']}")
                #         else:
                #             print(f"找不到电链路{u}-{v}的容量信息")
                #         # break
                #     else:
                #         print(f"边{u}-{v}是光链路")
                # else:
                #     print(f"边{u}-{v}不存在")
    # Step 1.3: 计算不需要重构通信对的延迟
    no_delays = {}
    for pair in no_recon_pairs:
        max_delay = 0
        old_path = old_optimal_paths.get(pair, [])
        for i in range(len(old_path) - 1):
            u, v = old_path[i], old_path[i + 1]
            # if network_topology.has_edge(u, v) and network_topology[u][v].get('type') == 'electrical':
            if network_topology.has_edge(u, v):
                capacity = network_topology[u][v]['capacity']
                flow = new_demand_matrix[pair]
                if capacity > 0:
                    max_delay = max(max_delay, flow / capacity)
                else:  # 容量不足时设为无穷大
                    max_delay = float('inf')

        no_delays[pair] = max_delay
    # Step 1.2: 批量更新电链路容量
    for (u, v), usage in link_usage.items():
        if network_topology[u][v]['capacity'] is not None:
            network_topology[u][v]['capacity'] = max(
                network_topology[u][v]['capacity'] - usage,
                0
            )
        else:
            print(f"警告：电链路 {u}-{v} 缺少容量信息")

    # # Step 1.3: 计算不需要重构通信对的延迟
    # no_delays = {}
    # for pair in no_recon_pairs:
    #     max_delay = 0
    #     old_path = old_optimal_paths.get(pair, [])
    #     for i in range(len(old_path) - 1):
    #         u, v = old_path[i], old_path[i + 1]
    #         # if network_topology.has_edge(u, v) and network_topology[u][v].get('type') == 'electrical':
    #         if network_topology.has_edge(u, v):
    #             capacity = network_topology[u][v]['capacity']
    #             flow = new_demand_matrix[pair]
    #             if capacity > 0:
    #                 max_delay = max(max_delay, flow / capacity)
    #             else:  # 容量不足时设为无穷大
    #                 max_delay = float('inf')
    #
    #     no_delays[pair] = max_delay

    # Step 2: 按流量需求将需要重构的通信对从大到小排序
    sorted_pairs = sorted(recon_pairs, key=lambda x: new_demand_matrix[x], reverse=True)

    # Step 3: 为每个通信对寻找最优电网络路径
    reconfigured_paths = {} # 初始化可重构的路径集合(之前已经找出了需要重构的通信对集合）
    no_reconfigured_paths = {} # 初始化不需要重构的路径集合
    delays = {} # 初始化延迟集合
    for pair in sorted_pairs:
        s, d = pair
        flow = new_demand_matrix[pair]
        # TODO: 使用Dijkstra算法或其他算法寻找电网络中的最优路径
        path = find_min_max_delay_path(network_topology, s, d, flow) # 找到电网络中的最优路径
        if path: # 如果找到路径
            # 计算路径的最大时延（遍历路径中的所有链路）
            max_delay = 0
            for u, v in zip(path[:-1], path[1:]):
                capacity_e = network_topology[u][v]['capacity']
                # 更新链路带宽
                if capacity_e >= flow:
                    network_topology[u][v]['capacity'] -= flow
                else:
                    network_topology[u][v]['capacity'] = 0
                delay = flow / capacity_e
                max_delay = max(max_delay, delay)
            reconfigured_paths[pair] = path # 将路径添加到可重构路径集合中
            delays[pair] = max_delay # 将最大时延添加到时延集合中
        else:
            reconfigured_paths[pair] = None #如果没有找到路径则设置为None
            delays[pair] = float('inf')  # 无可用路径
            print(f"无法找到路径：{pair}")

    return reconfigured_paths, delays,no_delays

# ------------------- 示例用法 -------------------
# ------------------- 示例用法（包含电和光网络） -------------------
if __name__ == "__main__":
    # 构建光电混合网络拓扑
    # G = nx.DiGraph()
    #
    # # 添加节点（终端和交换机）
    # nodes = ["t1", "t2","t3","t4", "tor1", "tor2","tor3","tor4", "os1", "os2","os3","os4","agg1","agg2","core1"]
    # G.add_nodes_from(nodes)
    #
    # # 添加电链路（容量单位为Gbps）
    # G.add_edge("t1", "tor1", type="electrical", capacity_e=10)  # t1→tor1（10G）
    # G.add_edge("t2", "tor2", type="electrical", capacity_e=10)
    # G.add_edge("t3", "tor3", type="electrical", capacity_e=10)
    # G.add_edge("t4", "tor4", type="electrical", capacity_e=10)
    # G.add_edge("tor1", "agg1", type="electrical", capacity_e=20)
    # G.add_edge("tor2", "agg1", type="electrical", capacity_e=20)
    # G.add_edge("tor3", "agg2", type="electrical", capacity_e=20)
    # G.add_edge("tor4", "agg2", type="electrical", capacity_e=20)
    # G.add_edge("agg1", "core1", type="electrical", capacity_e=40)
    # G.add_edge("agg2", "core1", type="electrical", capacity_e=40)
    # # 光网络
    # G.add_edge("tor1", "os1", type="optical", capacity_e=40)
    # G.add_edge("tor1", "os2", type="optical", capacity_e=40)
    # G.add_edge("tor1", "os3", type="optical", capacity_e=40)
    # G.add_edge("tor1", "os4", type="optical", capacity_e=40)
    # G.add_edge("tor2", "os1", type="optical", capacity_e=40)
    # G.add_edge("tor2", "os2", type="optical", capacity_e=40)
    # G.add_edge("tor2", "os3", type="optical", capacity_e=40)
    # G.add_edge("tor2", "os4", type="optical", capacity_e=40)
    # G.add_edge("tor3", "os1", type="optical", capacity_e=40)
    # G.add_edge("tor3", "os2", type="optical", capacity_e=40)
    # G.add_edge("tor3", "os3", type="optical", capacity_e=40)
    # G.add_edge("tor3", "os4", type="optical", capacity_e=40)
    # G.add_edge("tor4", "os1", type="optical", capacity_e=40)
    # G.add_edge("tor4", "os2", type="optical", capacity_e=40)
    # G.add_edge("tor4", "os3", type="optical", capacity_e=40)
    # G.add_edge("tor4", "os4", type="optical", capacity_e=40)

    # # 添加光链路（高速互联）
    # G.add_edge("os1", "os2", type="optical", capacity_o=100)  # os1↔os2（100G）
    # 创建测试拓扑
    G = build_hybrid_topology_shared_tor()  # 从函数中获取拓扑
    # print("---------------------------------------------------------")
    # 检查图的节点
    print("图的节点G.nodes:", G.nodes())  # 获取到的是所有的节点，包括交换机和服务器

    # 输出每条链路的类型
    print("--------------输出每条链路的类型----------------------------")
    for u, v, data in G.edges(data=True):
        print(f"链路 {u}→{v} 的类型为：{data['type']}")

    generator = TrafficGenerator(num_nodes=4)  # 从函数中获取流量生成器，输入的16是ToR的数量
    # # 获取 ToR 交换机和光交换机集合
    tor_switches = {node for node, data in G.nodes(data=True) if data.get('type') == 'tor'}
    print("tor_switches", tor_switches)
    optical_switches = {node for node, data in G.nodes(data=True) if data.get('type') == 'optical_switch'}
    print("光交换机节点为：", optical_switches)
    # 定义流量需求矩阵
    # new_demand = {
    #     ("t1", "t3"): 30,  # t1→t3需要30Gbps
    #     ("t2", "t4"): 20,  # t2→t4需要20Gbps
    #     ("t3", "t1"): 10  # t3→t1需要10Gbps
    # }
    # 获取流量需求矩阵
    # trafficGenerator = TrafficGenerator()
    # all_to_all = trafficGenerator.generate_all_to_all()
    # brust = trafficGenerator.generate_burst_traffic()

    print("===========直接从json文件中读取已经生成的流量矩阵===================")
    with open('traffic_simulation.json', 'r') as f:
        data = json.load(f)
        # 输出时间为0.12时候的流量需求矩阵作为all_to_all
        for record in data:
            if record['timestamp'] == 0.12:
                all_to_all_list = record['matrix']
                # 转换为矩阵形式
                all_to_all= np.array(all_to_all_list)
                print(all_to_all)
            else:
                # 输出时间为5.19时候的流量需求矩阵作为brust
                if record['timestamp'] == 5.19:
                    brust_list = record['matrix']
                    brust = np.array(brust_list)
                    print(brust)
    print("输出的all_to_all流量需求矩阵为:",all_to_all)
    print("输出的brust流量需求矩阵为:",brust)
    hybrid_flow=all_to_all+brust
    print("输出的混合流量需求矩阵为:",hybrid_flow)
    all_to_all_dict = {(i, j): all_to_all[i][j] for i in range(all_to_all.shape[0]) for j in range(all_to_all.shape[1])}
    hybrid_flow_dict = {(i, j): hybrid_flow[i][j] for i in range(hybrid_flow.shape[0]) for j in range(hybrid_flow.shape[1])}
    # 获取all_to_all通信对
    T_all_to_all = []
    for pair, demand in all_to_all_dict.items():
        # print("pair:",pair)
        # print("demand:",demand)
        if demand > 0:
            T_all_to_all.append(pair)
    for pair in T_all_to_all:
        print("pair:", pair)  # 输出的通信对的格式为（1,2），表示ToR1和ToR2

    # 将键从 (i, j) 转换为 ("ToR{i}", "ToR{j}")
    all_to_all_str_keys = {(f"ToR{i + 1}", f"ToR{j + 1}"): value for (i, j), value in all_to_all_dict.items()}
    # print("D_str_keys:",D_str_keys)

    # 将值从 numpy.ndarray 转换为浮点数
    all_to_all_float_values = {k: float(v) for k, v in all_to_all_str_keys.items()}

    # 生成通信对列表
    T_all_to_all = [pair for pair, demand in all_to_all_float_values.items() if demand > 0]
    print("生成all_to_all通信对列表", T_all_to_all)

    # 生成all_to_all+brust通信对
    T_hybird_flow = []
    for pair, demand in hybrid_flow_dict.items():
        # print("pair:",pair)
        # print("demand:",demand)
        if demand > 0:
            T_hybird_flow.append(pair)
    for pair in T_hybird_flow:
        print("pair:", pair)  # 输出的通信对的格式为（1,2），表示ToR1和ToR2

    # 将键从 (i, j) 转换为 ("ToR{i}", "ToR{j}")
    hybrid_str_keys = {(f"ToR{i + 1}", f"ToR{j + 1}"): value for (i, j), value in hybrid_flow_dict.items()}
    # print("D_str_keys:",D_str_keys)

    # 将值从 numpy.ndarray 转换为浮点数
    hybrid_float_values = {k: float(v) for k, v in hybrid_str_keys.items()}

    # 生成通信对列表
    T_hybird_flow = [pair for pair, demand in hybrid_float_values.items() if demand > 0]
    print("生成通信对列表", T_hybird_flow)

    # # 旧路径（光网络路径）
    # old_optimal_paths = {
    #     ("t1", "t3"): ["t1", "tor1", "os1", "os2", "tor2", "t3"],  # 经过os1→os2
    #     ("t2", "t4"): ["t2", "tor1", "os2", "tor2", "t4"],  # 经过os2
    #     ("t3", "t1"): ["t3", "tor2", "os1", "tor1", "t1"]  # 经过os1
    # }
    #
    # # 新路径（重构后）
    # new_optimal_paths = {
    #     ("t1", "t3"): ["t1", "tor1", "os2", "tor2", "t3"],  # 改走os2
    #     ("t2", "t4"): ["t2", "tor1", "os1", "tor2", "t4"],  # 改走os1
    #     ("t3", "t1"): ["t3", "tor2", "os1", "tor1", "t1"]  # 路径未变
    # }
    # 根据流量需求矩阵获得最优路径
    S1,path_t = allocate_switches_with_es(G, T_all_to_all, all_to_all_float_values,{"tor1", "tor2","tor3","tor4"},{"os1", "os2","os3","os4"},18 )
    # print("基本流量的最优路径为:",path_t)
    print("\n基本流量的最优路径为:")
    for pair, path in path_t.items():
        print(f"{pair} -> {path}")
    S2,path_tt = allocate_switches_with_es(G, T_hybird_flow, hybrid_float_values,{"tor1", "tor2","tor3","tor4"},{"os1", "os2","os3","os4"}, 40)
    # print("基本流量+突发流量的最优路径为:", path_tt)
    print("\n基本流量+突发流量的最优路径为:")
    for pair, path in path_tt.items():
        print(f"{pair} -> {path}")

    # print("=======================测试=====================")
    # print(type(path_t))
    # print(type(path_tt))
    # print("=======================测试=====================")
    # 执行优化算法
    reconfigured_paths, delays ,no_delays = optimize_reconfiguration(
        hybrid_float_values, G, path_t, path_tt
    )

    # 输出结果
    print("需要重构的通信对及电网络路径：")
    for pair, path in reconfigured_paths.items():
        if path is not None:
            print(f"{pair}: 电网络路径 {path}，最大时延 {delays[pair]:.2f} ms")
        else:
            print(f"{pair}: 无可用电路径")

    print("不需要重构的通信对及路径")
    for pair, path in path_t.items():
        # 如果通信对不在需要重构的通信对列表中（则保持原来的光链路）
        if pair not in reconfigured_paths:
            # print(f"{pair}: 光网络路径 {path},最大时延 {no_delays[pair]:.2f}")
            # 获取每条路径的带宽
            print(f"{pair}: 电网络路径 {path}，通信对的流量需求为：{hybrid_float_values[pair]}，最大时延 {no_delays[pair]:.2f} ms")



    # 输出所有链路的剩余容量
    print("==================所有链路的剩余容量=====================")
    for u, v, data in G.edges(data=True):
        if data.get('capacity') is not None:
            print(f"链路 {u}→{v} 的剩余容量为：{data['capacity']}")
    print("==================所有链路的剩余容量=====================")

    # TODO: 输出不需要重构的通信对及电网络路径
    # print("==================不需要重构的通信对=====================")
    # print("==================找出电链路并且更新电链路的剩余容量==================")
    # for pair, path in path_t.items():
    #     if pair not in reconfigured_paths:
    #         # 遍历路径中的链路
    #         for i in range(len(path)-1):
    #             u=path[i]
    #             v=path[i+1]
    #             # 检查图中是否存在该链路
    #             if G.has_edge(u, v):
    #                 print(f"链路: ({u}, {v})")
    #                 if G[u][v].get('type') == 'electrical':
    #                     print(f"路径{path}的链路: ({u}, {v}) 为电链路")
    #                     if G[u][v].get('capacity') is not None:
    #                         print(f"路径{path}的链路: ({u}, {v}) 的剩余容量为{G[u][v]['capacity']}")
    #                         G[u][v]['capacity'] -= hybrid_float_values[pair]
    #                         print(f"更新后的链路容量为：{G[u][v]['capacity']}")
    #                     else:
    #                        print(f"找不到链路容量信息")
    #                     break
    #                 else:
    #                     print(f"路径{path}的链路: ({u}, {v}) 为光链路")
    #             else:
    #                 print(f"警告: 路径中 ({u}, {v}) 不是图中的有效链路")

            # for (u,v) in path:
            #     if G.has_edge(u, v) and G[u][v].get('link_type') == 'electrical':
            #         print(f"{pair}: 电网络路径 {path}的链路{(u,v)}为电链路")
            #         break
            # print(f"{pair}: 电网络路径 {path}")


